﻿
using Xacml.Core.Policy;
using System.Collections;

namespace Xacml.Core.Runtime
{
  public class Target
  {
    private TargetElement _target;
    private TargetEvaluationValue _evaluationValue;
    private ResourceTargetItems _resources;
    private SubjectTargetItems _subjects;
    private ActionTargetItems _actions;

    public Target(TargetElement target)
    {
      this._target = target;
      this._resources = new ResourceTargetItems((ResourcesElement) this._target.Resources);
      this._subjects = new SubjectTargetItems((SubjectsElement) this._target.Subjects);
      this._actions = new ActionTargetItems((ActionsElement) this._target.Actions);
    }

    public TargetEvaluationValue Evaluate(EvaluationContext context)
    {
      this._evaluationValue = TargetEvaluationValue.NoMatch;
      context.Trace("Evaluating Resource...");
      context.AddIndent();
      TargetEvaluationValue targetEvaluationValue1 = this._resources.Evaluate(context, (Xacml.Core.Context.TargetItemBase) context.CurrentResource);
      context.TraceContextValues();
      context.Trace("Target item result: {0}", (object) targetEvaluationValue1);
      context.RemoveIndent();
      context.Trace("Evaluating Action...");
      context.AddIndent();
      TargetEvaluationValue targetEvaluationValue2 = this._actions.Evaluate(context, (Xacml.Core.Context.TargetItemBase) context.ContextDocument.Request.Action);
      context.TraceContextValues();
      context.Trace("Target item result: {0}", (object) targetEvaluationValue2);
      context.RemoveIndent();
      context.Trace("Evaluating Subjects...");
      context.AddIndent();
      if (targetEvaluationValue2 == TargetEvaluationValue.Match && targetEvaluationValue1 == TargetEvaluationValue.Match)
      {
        foreach (Xacml.Core.Context.SubjectElement subjectElement in (CollectionBase) context.ContextDocument.Request.Subjects)
        {
          context.Trace("Evaluating Subject: {0}", (object) subjectElement.SubjectCategory);
          TargetEvaluationValue targetEvaluationValue3 = this._subjects.Evaluate(context, (Xacml.Core.Context.TargetItemBase) subjectElement);
          context.TraceContextValues();
          if (targetEvaluationValue3 == TargetEvaluationValue.Indeterminate)
            this._evaluationValue = TargetEvaluationValue.Indeterminate;
          else if (targetEvaluationValue3 == TargetEvaluationValue.Match)
          {
            this._evaluationValue = TargetEvaluationValue.Match;
            context.RemoveIndent();
            context.Trace("Target item result: {0}", (object) this._evaluationValue);
            return this._evaluationValue;
          }
        }
        context.RemoveIndent();
        context.Trace("Target item result: {0}", (object) this._evaluationValue);
        return this._evaluationValue;
      }
      context.Trace("Actions or Resources does not Match so Subjects will not be evaluated");
      if (targetEvaluationValue1 == TargetEvaluationValue.Indeterminate || targetEvaluationValue2 == TargetEvaluationValue.Indeterminate)
      {
        context.RemoveIndent();
        return TargetEvaluationValue.Indeterminate;
      }
      context.RemoveIndent();
      return TargetEvaluationValue.NoMatch;
    }
  }
}
